#include <iostream>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include "Comm.hpp"
#include <netinet/in.h>
#include <arpa/inet.h>
#include "InetAddr.hpp"
#include "Thread.hpp"

void Usage(std::string proc)
{
    std::cout << "Usage: \n\t" << proc << " local_ip local_port\n"
              << std::endl;
}

class ThreadData
{
public:
    int _socket;
    InetAddr _InetAddr;

    ThreadData(int sockfd, InetAddr &inetaddr) : _socket(sockfd), _InetAddr(inetaddr)
    {
    }
};

void Recver(ThreadData &data) // 这两个函数是要被线程调用回来的
{
    int sockfd = data._socket;
    while (true)
    {
        char buffer[1024];
        struct sockaddr_in temp;
        socklen_t len = sizeof temp;

        ssize_t m = recvfrom(sockfd, buffer, sizeof buffer - 1, 0, (struct sockaddr *)&temp, &len);
        if (m > 0)
        {
            buffer[m] = 0;
            std::cerr << "Server say: " << buffer << std::endl;
        }
        else
            break;
    }
}

void Sender(ThreadData &data) // 这两个函数是要被线程调用回来的
{
    int sockfd = data._socket;
    struct sockaddr_in addr = data._InetAddr.getaddr();
    socklen_t len = sizeof addr;
    while (1)
    {
        std::string in_buffer;
        std::cout << "Please Enter: " << std::endl;
        std::getline(std::cin, in_buffer);

        size_t n = sendto(data._socket, in_buffer.c_str(), in_buffer.size(), 0, (struct sockaddr *)&addr, len);
        if (n > 0)
        {
        }
        else
        {
            break;
        }
    }
}

int main(int argc, char *argv[])
{
    if (argc != 3) // 参数数量
    {
        Usage(argv[0]);
        return Usage_Err;
    }

    std::string serverip = argv[1];           // ip地址
    uint16_t serverport = std::stoi(argv[2]); // 端口号

    // 创建套接字
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        std::cerr << "Socket Error! " << strerror(errno) << std::endl;
        return 1;
    }

    std::cout << "Create socket success!" << std::endl;
    // client 不需要进行bind,客户端很多，需要随机绑定
    // client 需要bind,但是不需要显示bind,

    struct sockaddr_in server;
    bzero(&server, sizeof server);

    server.sin_family = AF_INET;
    server.sin_port = htons(serverport);
    server.sin_addr.s_addr = inet_addr(serverip.c_str());

    // udp 使全双工的，可以同时读写
    // 创建线程
    InetAddr inetaddr(server);
    ThreadData data(sock, inetaddr);
    Thread<ThreadData> recver(Recver, "recver", data); //  const char[]  需要 const string 才能传递
    Thread<ThreadData> sender(Sender, "sender", data);
    recver.Start();
    sender.Start();

    // while (1)
    // {
    //     std::string in_buffer;
    //     std::cout << "Please Enter: " << std::endl;
    //     std::getline(std::cin, in_buffer);

    //     size_t n = sendto(sock, in_buffer.c_str(), in_buffer.size(), 0, (struct sockaddr *)&server, sizeof server);
    //     if (n > 0)
    //     {
    //         char buffer[1024];
    //         struct sockaddr_in temp;
    //         socklen_t len = sizeof temp;

    //         ssize_t m = recvfrom(sock, buffer, sizeof buffer - 1, 0, (struct sockaddr *)&temp, &len);

    //         if (m > 0)
    //         {
    //             buffer[m] = 0;
    //             std::cout << "Server # say: " << buffer << std::endl;
    //         }
    //         else
    //             break;
    //     }
    //     else
    //     {
    //         break;
    //     }
    // }

    recver.Join();
    sender.Join();

    close(sock);
}